package com.middlegroup.common.utils;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;

/**
 * @author pc
 */
public class RSAUtils {
    public static final String KEY_ALGORITHM = "RSA";
    private static final int MAX_ENCRYPT_BLOCK = 117;
    private static final int MAX_DECRYPT_BLOCK = 128;

    public RSAUtils() {
    }

    public static PublicKey loadPublicKey(InputStream pemFileInputStream) {
        return readPublicKey(readPEMFile(pemFileInputStream));
    }

    public static PrivateKey loadPrivateKey(InputStream pkcs8PemFileInputStream) {
        return readPrivateKey(readPEMFile(pkcs8PemFileInputStream));
    }

    public static PublicKey loadPublicKey(String pemFile) {
        return readPublicKey(readPEMFile(pemFile));
    }

    public static PrivateKey loadPrivateKey(String pkcs8PemFile) {
        return readPrivateKey(readPEMFile(pkcs8PemFile));
    }

    public static String readPEMFile(String filename) {
        try {
            return readPEMFile((InputStream)(new FileInputStream(filename)));
        } catch (FileNotFoundException var2) {
            throw new RuntimeException(var2);
        }
    }

    public static String readPEMFile(InputStream stream) {
        if(null != stream) {
            BufferedReader in = null;
            StringBuilder ret = new StringBuilder();

            try {
                in = new BufferedReader(new InputStreamReader(stream, "ASCII"));

                for(String line = in.readLine(); null != line; line = in.readLine()) {
                    if(!line.startsWith("-----BEGIN ") && !line.startsWith("-----END ")) {
                        ret.append(line);
                        ret.append("\n");
                    }
                }

                String ex = ret.toString();
                return ex;
            } catch (Exception var16) {
                throw new RuntimeException(var16);
            } finally {
                try {
                    stream.close();
                } catch (Exception var15) {
                    var15.printStackTrace();
                }

                if(null != in) {
                    try {
                        in.close();
                    } catch (Exception var14) {
                        var14.printStackTrace();
                    }
                }

            }
        } else {
            return null;
        }
    }

    public static PrivateKey readPrivateKey(String pkcs8Base64String) {
        byte[] keyByte = Base64Utils.decode(pkcs8Base64String);

        try {
            KeyFactory ex = KeyFactory.getInstance("RSA");
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyByte);
            RSAPrivateKey privateKey = (RSAPrivateKey)ex.generatePrivate(privateKeySpec);
            return privateKey;
        } catch (InvalidKeySpecException | NoSuchAlgorithmException var5) {
            throw new RuntimeException(var5);
        }
    }

    public static PublicKey readPublicKey(String pkcs8Base64String) {
        byte[] keyByte = Base64Utils.decode(pkcs8Base64String);

        try {
            X509EncodedKeySpec ex = new X509EncodedKeySpec(keyByte);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(ex);
            return publicKey;
        } catch (InvalidKeySpecException | NoSuchAlgorithmException var5) {
            throw new RuntimeException(var5);
        }
    }

    public static byte[] decryptByPrivateKey(byte[] encryptedData, PrivateKey privateKey) {
        try {
            KeyFactory ex = KeyFactory.getInstance("RSA");
            Cipher cipher = Cipher.getInstance(ex.getAlgorithm());
            cipher.init(2, privateKey);
            return cipher.doFinal(encryptedData);
        } catch (Exception var4) {
            throw new RuntimeException(var4);
        }
    }

    public static String encryptByPublicKey(String content, PublicKey publicKey, String charset) {
        try {
            Cipher e = Cipher.getInstance("RSA");
            e.init(1, publicKey);
            byte[] data = charset != null && !charset.isEmpty()?content.getBytes(charset):content.getBytes();
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;

            for(int i = 0; inputLen - offSet > 0; offSet = i * 117) {
                byte[] cache;
                if(inputLen - offSet > 117) {
                    cache = e.doFinal(data, offSet, 117);
                } else {
                    cache = e.doFinal(data, offSet, inputLen - offSet);
                }

                out.write(cache, 0, cache.length);
                ++i;
            }

            byte[] encryptedData = Base64Utils.encode(out.toByteArray());
            out.close();
            return new String(encryptedData, "ASCII");
        } catch (Exception var11) {
            throw new RuntimeException(var11);
        }
    }

    public static String encryptByPrivateKey(String content, PrivateKey privateKey, String charset) {
        try {
            Cipher e = Cipher.getInstance("RSA");
            e.init(1, privateKey);
            byte[] data = charset != null && !charset.isEmpty()?content.getBytes(charset):content.getBytes();
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;

            for(int i = 0; inputLen - offSet > 0; offSet = i * 117) {
                byte[] cache;
                if(inputLen - offSet > 117) {
                    cache = e.doFinal(data, offSet, 117);
                } else {
                    cache = e.doFinal(data, offSet, inputLen - offSet);
                }

                out.write(cache, 0, cache.length);
                ++i;
            }

            byte[] encryptedData = Base64Utils.encode(out.toByteArray());
            out.close();
            return new String(encryptedData, "ASCII");
        } catch (Exception var11) {
            throw new RuntimeException(var11);
        }
    }

    public static String decryptByPrivateKey(String content, PrivateKey privateKey, String charset) {
        try {
            Cipher e = Cipher.getInstance("RSA");
            e.init(2, privateKey);
            byte[] encryptedData = Base64Utils.decode(content);
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;

            for(int i = 0; inputLen - offSet > 0; offSet = i * 128) {
                byte[] cache;
                if(inputLen - offSet > 128) {
                    cache = e.doFinal(encryptedData, offSet, 128);
                } else {
                    cache = e.doFinal(encryptedData, offSet, inputLen - offSet);
                }

                out.write(cache, 0, cache.length);
                ++i;
            }

            byte[] decryptedData = out.toByteArray();
            out.close();
            return charset != null && !charset.isEmpty()?new String(decryptedData, charset):new String(decryptedData);
        } catch (Exception var11) {
            throw new RuntimeException(var11);
        }
    }

    public static String decryptByPublicKey(String content, PublicKey publicKey, String charset) {
        try {
            Cipher e = Cipher.getInstance("RSA");
            e.init(2, publicKey);
            byte[] encryptedData = Base64Utils.decode(content);
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;

            for(int i = 0; inputLen - offSet > 0; offSet = i * 128) {
                byte[] cache;
                if(inputLen - offSet > 128) {
                    cache = e.doFinal(encryptedData, offSet, 128);
                } else {
                    cache = e.doFinal(encryptedData, offSet, inputLen - offSet);
                }

                out.write(cache, 0, cache.length);
                ++i;
            }

            byte[] decryptedData = out.toByteArray();
            out.close();
            return charset != null && !charset.isEmpty()?new String(decryptedData, charset):new String(decryptedData);
        } catch (Exception var11) {
            throw new RuntimeException(var11);
        }
    }

    public static boolean verifySign(String signType, byte[] data, PublicKey publicKey, String sign) throws Exception {
        Signature signature = Signature.getInstance(signType);
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(Base64Utils.decode(sign));
    }

    public static String sign(String signType, byte[] data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance(signType);
        signature.initSign(privateKey);
        signature.update(data);
        return new String(Base64Utils.encode(signature.sign()));
    }

    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(2, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;

        for(int i = 0; inputLen - offSet > 0; offSet = i * 128) {
            byte[] cache;
            if(inputLen - offSet > 128) {
                cache = cipher.doFinal(encryptedData, offSet, 128);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }

        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    public static String decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(2, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;

        for(int i = 0; inputLen - offSet > 0; offSet = i * 128) {
            byte[] cache;
            if(inputLen - offSet > 128) {
                cache = cipher.doFinal(encryptedData, offSet, 128);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }

        byte[] decryptedData = out.toByteArray();
        out.close();
        return Base64.encode(decryptedData);
    }

    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(1, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;

        for(int i = 0; inputLen - offSet > 0; offSet = i * 117) {
            byte[] cache;
            if(inputLen - offSet > 117) {
                cache = cipher.doFinal(data, offSet, 117);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }

        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    public static String encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(1, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;

        for(int i = 0; inputLen - offSet > 0; offSet = i * 117) {
            byte[] cache;
            if(inputLen - offSet > 117) {
                cache = cipher.doFinal(data, offSet, 117);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }

            out.write(cache, 0, cache.length);
            ++i;
        }

        byte[] encryptedData = out.toByteArray();
        out.close();
        return Base64.encode(encryptedData);
    }
}
